﻿//-----------------------------------------------------------------------
// <copyright file="RenderEngine.cs" company="Flaxen Geo">
//    Copyright (c) 2011, Michael P. Gerlek.  All rights reserved.
// </copyright>
//
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, 
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of Flaxen Geo nor the names of its contributors may be 
//   used to endorse or promote products derived from this software without 
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------

namespace Flaxen.SlimDXControlLib
{
    using System;
    using SlimDX.Direct3D10;
    using Device = SlimDX.Direct3D10_1.Device1;

    /// <summary>
    /// This is the base class users should use for implementing their own rendering logic:
    /// specifically, you need to create a device and then create the SharedTexture object,
    /// and then implement the Render method to do the actual pipeline.  We explicitly do not
    /// provide any of the underlying D3D code here, so users are free to do as they please 
    /// for their own apps.
    /// </summary>
    public abstract class RenderEngine : IDisposable
    {
        /// <summary>
        /// Gets or sets the texture used by WPF's D3DImage.
        /// </summary>
        public Texture2D SharedTexture { get; set; }

        /// <summary>
        /// Gets or sets the D3D device.
        /// </summary>
        protected Device Device { get; set; }

        /// <summary>
        /// Gets or sets the window width of the render engine's target.
        /// </summary>
        protected int WindowWidth { get; set; }

        /// <summary>
        /// Gets or sets the window height of the render engine's target.
        /// </summary>
        protected int WindowHeight { get; set; }

        /// <summary>
        /// Gets or sets the SlimDXControl associated with this render engine.
        /// </summary>
        protected SlimDXControl Control { get; set; }

        /// <summary>
        /// Implement this routine to constuct the D3D device and any other needed setup.
        /// Be sure to call base.Initialize(control) from your method.
        /// </summary>
        /// <param name="control">The SlimDXControl associated with this renderer.</param>
        public abstract void Initialize(SlimDXControl control);

        /// <summary>
        /// Implement this routine to construct (or reconstruct) any size-dependent objects
        /// not handled by your Initialize() routine.
        /// Be sure to call base.Reinitialize() from your method.
        /// </summary>
        /// <param name="width">width of the render target, in pixels</param>
        /// <param name="height">height of the render target, in pixels</param>
        public abstract void Reinitialize(int width, int height);

        /// <summary>
        /// Implement this to perform the actual rendering process.
        /// (There is no base.Render() method to be called.)
        /// </summary>
        public abstract void Render();

        /// <summary>
        /// Implement this to dispose of any managed objects in your class.
        /// Be sure to call base.DisposeManaged() at the end of your method.
        /// </summary>
        protected virtual void DisposeManaged()
        {
            return;
        }

        /// <summary>
        /// Implement this to dispose of any unmanaged objects in your class.
        /// Be sure to call base.DisposeUnmanaged() at the end of your method.
        /// </summary>
        protected virtual void DisposeUnmanaged()
        {
            return;
        }

        #region IDisposable
        ~RenderEngine()
        {
            Dispose(false);
        }

        private bool m_disposed = false;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                if (disposing)
                {
                    DisposeManaged();
                }

                DisposeUnmanaged();

                m_disposed = true;
            }
        }
        #endregion
    }
}
